"""
商品视图
"""
import decimal
import traceback
import json
import logging

from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication
from django.shortcuts import render
from django.db.models import Q
from rest_framework import permissions
from rest_framework.decorators import action

from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView, ListAPIView, UpdateAPIView, CreateAPIView, RetrieveAPIView
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from django.forms.models import model_to_dict
from django.db import transaction

from account.models import Account
from goods.models import Goods, Picture, GoodsOrder
from goods.serializers import GoodsSerializer
from common.redis_utils import RDS
from goods.utils import create_order, create_sub_order
from pay.utils import AliPayView
from common.utils import LargeResultsSetPagination

from drf_yasg2.utils import swagger_auto_schema
from drf_yasg2 import openapi

logger = logging.Logger('log')

rds = RDS()
goods_key = 'goods'
order_key = 'order'


class AddGoods(GenericAPIView):
    """
    添加商品
    """
    serializer_class = GoodsSerializer
    permission_classes = [permissions.IsAuthenticated]
    request_body = openapi.Schema(type=openapi.TYPE_OBJECT,
                                  required=['name', 'price', 'count'], properties=
                                  {'name': openapi.Schema(type=openapi.TYPE_STRING, description='商品名称'),
                                   'price': openapi.Schema(type=openapi.TYPE_STRING, description='商品价格'),
                                   'count': openapi.Schema(type=openapi.TYPE_STRING, description='商品数量')}
                                  )

    @swagger_auto_schema(method='post', request_body=request_body, )
    @action(methods=['post'], detail=False, )
    def post(self, request):
        try:
            data = request.data
            name = data.get('name')
            price = data.get('price')
            count = data.get('count')
            desc = data.get('desc', '')
            picture_list = data.get('picture_list')
            goods, _ = Goods.objects.get_or_create(name=name)
            goods.price = decimal.Decimal(price)
            goods.count = int(count)
            goods.desc = desc
            goods.save()
            if picture_list:
                for picture in picture_list:
                    obj = Picture.objects.create(goods_id=goods.id, url_path=picture)
                    obj.save()
            result = self.get_serializer(goods).data
            return Response({'code': 200, 'data': result})
        except:
            error = traceback.format_exc()
            logger.error(error)
            return Response({'code': 500, 'error': error})


class SearchGoods(RetrieveAPIView):
    """
    查询商品

    当前只安装商品id以及商品名称去查
    """
    serializer_class = GoodsSerializer
    query_param = [openapi.Parameter(name='q', in_=openapi.IN_QUERY, description="查询条件", type=openapi.TYPE_STRING),
                   openapi.Parameter(name='size', in_=openapi.IN_QUERY, description="页数大小", type=openapi.TYPE_NUMBER),
                   openapi.Parameter(name='page', in_=openapi.IN_QUERY, description="页码", type=openapi.TYPE_NUMBER),
                   ]

    @swagger_auto_schema(method='get', manual_parameters=query_param)
    @action(methods=['get'], detail=False)
    def get(self, request):
        data = request.query_params
        q = data.get('q')
        if not q:
            result_list = Goods.objects.order_by('-id').all()
        else:
            result_list = Goods.objects.filter(Q(name__icontains=q) | Q(desc__icontains=q)).order_by('-id')
        total_count = result_list.count()

        # 实例化分页对象
        page_cursor = LargeResultsSetPagination()
        # 分页
        data_list = page_cursor.paginate_queryset(result_list, request, view=self)

        data_list = self.get_serializer(data_list, many=True).data
        result = {'code': 200, 'data': data_list, 'total_count': total_count}
        return Response(result)


class GetGoodsInfo(APIView):
    """
    获取商品详细信息
    """
    serializer_class = GoodsSerializer
    query_param = openapi.Parameter(name='goods_id', in_=openapi.IN_QUERY, description="商品id", type=openapi.TYPE_STRING)

    @swagger_auto_schema(method='get', manual_parameters=[query_param])
    @action(methods=['get'], detail=False)
    def get(self, request):
        data = request.query_params
        goods_id = data.get('goods_id')
        goods = Goods.objects.filter(id=goods_id).first()
        goods_data = GoodsSerializer(goods).data
        info_picture_list = Picture.objects.filter(goods_id=goods_id).values_list('url_path', flat=True)
        info_picture_list = list(info_picture_list)
        goods_data.update({'info_picture_list': info_picture_list})
        return Response({'code': 200, 'data': goods_data})


class AddCartGoods(CreateAPIView):
    """
    添加购物车
    """
    permission_classes = [permissions.AllowAny, ]
    serializer_class = GoodsSerializer

    def post(self, request, *args, **kwargs):
        user = request.user
        data = request.data
        goods_id = int(data.get('goods_id'))
        count = int(data.get('count'))
        # 验证商品是否存在
        goods = Goods.objects.get(id=goods_id)
        if not goods:
            return Response({'code': 405})
        # 验证数量是否可用
        real_count = goods.get_available_count()
        if real_count < count:
            return Response({'code': 406})
        try:
            with transaction.atomic():
                # 加入redis缓存中
                rds_goods = rds.get_hash(user.id, goods_id)
                # 购物车中已有数据，只增加数量即可, 没有数据，更新数据
                if rds_goods:
                    rds.update_hash_count(name=user.id, key=goods_id, count=count)
                else:
                    rds_result = rds.set_hash(name=user.id, mapping={goods_id: count})
                    if not rds_result:
                        return Response({'code': 500, 'message': '数据异常'})

                goods.add_lock_count(count)
            data = rds.get_hash_all(user.id)
            return Response({'code': 200, 'message': 'success', 'data': data})
        except:
            error = traceback.format_exc()
            print('AddCartGoods', error)
            return Response({'code': 500, 'message': error})


class UpdateCartGoods(GenericAPIView):
    """
    修改购物车产品数据
    """
    serializer_class = GoodsSerializer
    request_body = openapi.Schema(type=openapi.TYPE_OBJECT,
                                  required=['new_password', 'username', 'password'],
                                  properties=
                                  {
                                      'username': openapi.Schema(type=openapi.TYPE_STRING, description='用户名'),
                                      'password': openapi.Schema(type=openapi.TYPE_STRING, description='旧密码'),
                                      'new_password': openapi.Schema(type=openapi.TYPE_STRING, description='新密码')
                                  }
                                  )

    @swagger_auto_schema(method='post', request_body=request_body, )
    @action(methods=['post'], detail=False, )
    def post(self, request):
        user = request.user
        data = request.data
        goods_id = data.get('goods_id')
        count = int(data.get('count'))
        type = int(data.get('type'))
        if type == 1:
            rds.update_hash_count(user.id, goods_id, count)
        else:
            rds.update_hash_count(user.id, goods_id, 0 - count)
        data = rds.get_hash_all(user.id)
        return Response({'code': 200, 'data': data})


class DeleteCartGoods(APIView):
    """
    删除购物车商品
    """

    def post(self, request):
        try:
            user = request.user
            data = request.data
            goods_id = int(data.get('goods_id'))
            # 1、删除redis中对应的数据 2、将锁定的产品数量释放
            with transaction.atomic():
                cart_data = rds.get_hash_all(user.id)
                count = cart_data.get(goods_id)
                rds.del_hash(user.id, goods_id)
                goods = Goods.objects.get(id=goods_id)
                goods.reduce_lock_count(count)
            result = rds.get_hash_all(user.id)
            return Response({'code': 200, 'data': result})
        except:
            error = traceback.format_exc()
            print('DeleteCartGoods', error)
            return Response({'code': 500, 'message': error})


class CreateOrder(APIView):
    """
    创建商品订单
    """

    def post(self, request):
        user = request.user
        data = request.data
        goods_list = data.get('goods_list')
        pay_type = data.get('pay_type')
        # TODO 注意goods_list 格式

        sub_order_list = []
        # 创建主订单
        order = create_order(user, pay_type)
        for goods in goods_list:
            goods_id = goods.get('goods_id')
            count = int(goods.get('count'))
            # 创建子订单
            sub_order = create_sub_order(order.id, goods_id, count, user.id)
            sub_order_list.append(sub_order)
        rds.set_rds(order_key, user.id, order.order_id)
        return Response({'code': 200, 'data': {'order_id': order.order_id, 'total_price': order.total_price}})


class GetPayURl(APIView):
    """
    获取支付链接
    """

    query_param = openapi.Parameter(name='order_id', in_=openapi.IN_QUERY, description="订单id",
                                    type=openapi.TYPE_STRING)

    @swagger_auto_schema(method='get', manual_parameters=[query_param])
    @action(methods=['get'], detail=False)
    def get(self, request):
        user = request.user
        data = request.query_params
        order_id = data.get('order_id')
        rds_order_id = json.loads(rds.get_rds(order_key, user.id))
        # redis无对应订单号
        if order_id != rds_order_id:
            return Response({})
        order = GoodsOrder.objects.filter(order_id=order_id).first()
        if not order:
            return
        if order.pay_status != 0:
            return

        # 实例化自定义alipay对象
        ali_obj = AliPayView()
        # 调用实例方法
        url = ali_obj.get_pay_url(order_id, int(order.total_price), subject='购物车收费')

        # 修改订单状态
        order.pay_status = 1
        order.save()
        # TODO 将订单号数据写redis

        return Response({'code': 200, 'data': {'url': url}})


class GetOrderResult(APIView):
    """
    获取订单结果
    """

    def get(self, request):

        data = request.query_params
        order_id = data.get('out_trade_no')

        order = GoodsOrder.objects.get(order_id=order_id)
        if order.pay_status not in [1]:
            return Response({'code': 406})

        ali_obj = AliPayView()
        response = ali_obj.get_pay_result(order_id)
        # 支付成功
        if response['code'] == '10000':
            order.pay_status = 2
            order.save()
            # TODO 删除redis中的订单数据
            return Response({'code': 200})
        else:  # 支付失败
            # TODO 支付失败后，重复查询3次，每次间隔1s
            pass


